home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
cmln1085.arc
/
TURBOGSX.HDC
< prev
next >
Wrap
Text File
|
1986-02-27
|
29KB
|
550 lines
@style{spacing 2 lines, notes endnote, indent 5 chars, footpush
no, leftmargin 10 chars, rightmargin 10 chars}
@begin{verbatim}
@CENTER{
----------------------------------------------------
| A TURBO GRAPHICS SHELL |
| Building an Interface to GSX Graphics |
| in Turbo Pascal for the DEC Rainbow |
----------------------------------------------------
Hubert D. Callihan, Ph.D.
University of Pittsburgh at Johnstown}
@end{verbatim}
@flushleft{Rainbow Graphics Dilemma}
Imagine yourself with a DEC Rainbow complete with graphics option
configured and ready to run. You load the Rainbow Graphics
Interpreter and demos provided by DEC and you proceed to witness
an impressive graphics demonstration exploiting many of the
features including multicolor lines, text in various sizes as
well as colors and orientations, fast polygonal line and circle
generation and fairly fast color fill of regions using a
multitude of possible colors, hatch styles and dithers. You are
convinced you bought the proper graphics computer.
You are now ecstatic and are soon ready to do some of your own
programming to exploit the available graphics calls. To
your surprise, you find from the Rainbow Graphics Programmer's
Manual that you must learn 8086 assembly language to do it unless
you are willing to spend $500 for Mark William's C language from
DEC. Quite frankly, you would settle for an interface in Pascal
or even MBASIC-86 but none can be found. Since you are neither
independently wealthy nor totally familiar with C nor 8086
assembly, you decide to explore alternatives. After much effort
searching a multitude of references you find no interfaces
available, so you decide to write the interface yourself in the
language of your choice.
The above scenario is a typical one for Rainbow owners wanting to
program their machines to exploit the powerful graphics kernel
subroutines available within the Graphics System Extension (GSX)
provided for the Rainbow by Digital Research, Inc. Most users
who are also programmers may have neither the time nor the
inclination to write the necessary interface software. I faced
the problem, had the inclination, and took the time. So in this
article I will supply some basic logic to do the interface and
also provide some Pascal code to implement it. The complete
Pascal source code is available on disk or hardcopy. The result
will be a working inexpensive and efficient graphics software
library in Pascal that will provide a nearly interpreter-like
graphics software development environment. If you do not own a
Rainbow but wish to interface GSX to Pascal, you too should find
it valuable since GSX is available for other microcomputers.
@flushleft{Enter Turbo Pascal!}
It made sense to me that if such an interface could be provided
for a popular compiler it would indeed enhance a GSX-equipped
machine's potential for graphics software development. Since
Pascal is my language choice and since I've had the CP/M-86
version of Borland International's Turbo Pascal running on a
Rainbow at UPJ for nearly a year with great success, I decided to
use it to write the interface to the GSX kernel.@foot{Turbo
Pascal V2.0 Reference Manual. Borland International, 4113 Scotts
Valley Drive, Scotts Valley, CA 95066.} The choice, I believe,
was a wise one since Turbo Pascal has been highly acclaimed as
being a versatile, inexpensive ($49.95 + $5.00 shipping), and
excellent performer.@foot{Tom Wadlow. Turbo Pascal. @i[BYTE],
July 1984, vol. 9, no. 7, pp. 267-278.}@foot{David D. Clark.
Turbo Pascal, v.1.01. @i[Dr. Dobb's Journal], June 1984, no. 92,
pp. 74-78.}@foot{Alan R. Miller. The Perfect Pascal for CP/M.
@i[Interface Age], January 1984, pp. 90-92.}@foot{Richard Rodman.
Turbo Pascal V2.0. @i[Computer Language], Premier Issue, 1984,
pp. 78-79}@foot{Michael Main, Bob Johnson, Richard Balay, Peter
Baker, Richard Cichelli, Allan McCoy, Donald Slaughter. Review
Feedback (Turbo Pascal), @i[BYTE], October 1984, vol. 9, no. 11,
pp. 307-308.}@foot{Harry Demarest, Donald Simpson, and Herbert
Kanner. Turbo Tidbits (Letters to the Editor), @i[Dr. Dobb's
Journal], no. 96, October 1984, pp. 12-13} So far my
experience with it has given me neither reason to seriously
question any of the previous accolades heaped upon it by its
reviewers nor to disagree with its weaknesses which are few and,
in my judgment, unimportant for micro-based GSX graphics
development. Borland's latest version (2.0) is used for
development of procedures for this article. Using an earlier
version should not be a handicap.
In what follows, I will present essential information along with
procedures to permit the Turbo Pascal programmer to perform
system calls under CP/M-86 to the Graphics Device Operating
System (GDOS) in GSX. The complete set of procedures is
included. You will soon find the manner in which arguments are
passed to subprograms is quite consistent with documented
requirements in GSX.@foot{Digital Equipment Corporation.
@I[Rainbow GSX-86 Programmer's Reference Manual], no.
AA-V526A-TV} In addition, those with non-Rainbow systems
running GSX under CP/M-86 or CP/M-80 should find that only the
low-level procedure "CALLGDOS" containing inline machine code
needs to be changed slightly to accommodate other CPUs. It may
also be true that some of the device-specific ESCAPE functions
would need to be tailored to the functions supported by other
device drivers. An article by William Wong in the July 1984
issue of @i[Microsystems] describes GSX in detail including the
calling procedure for 8- and 16-bit CP/M, Concurrent CP/M,
Concurrent DOS, PC-DOS, and MS-DOS to permit access to
GSX.@foot{William G. Wong. Digital Research's GSX: Graphics
Portability. @i[Microsystems], July 1984, vol. 5, no. 7, pp.
74-82.} This should be of great help to Turbo Pascal programmers
wishing to implement "CALLGDOS" on other systems.
@flushleft{GSX Essentials}
If you've ever programmed graphics operations on an Apple II or
other graphics devices, you've no doubt experienced the
frustration of tailoring the software package to accommodate
widely divergent hardware approaches to graphics. There could be
as many versions of one program as there are different devices to
perform the graphics. Such device-specific software development
is extremely unproductive where portability is a primary concern
as it is in commercial software development. Of course the
solution to such a dilemma is graphics standardization once we
all know and agree upon what we want as part of that standard
graphics kernel. When put into place as part of an operating
system's kernel of low-level call resources, such a standard
would provide any supported language the ability to "see" the
graphics kernel's resources from an outer shell perspective.
Quite apart from the shell and transparent to it, the graphics
kernel manages at a lower level all requests from the shell to
the device-specific functions such as line drawing, text display,
color filling, etc. At the shell level, I/O devices are
abstracted according to their general physical function such as
locator, valuator, string, and choice input devices with sample
or request modes available as the devices can support them.
The Graphics Kernel System (GKS) is a rich set of two-dimensional
utilities proposed as a first international standard for graphics
functionality which has evolved over a period of years since
about 1963.@foot{ACM SIGGRAPH. @i[Computer Graphics Special GKS
Issue], Feb. 1984.}@foot{Peter R. Bono, Jose L. Encarnacoa, F.
Robert A. Hopgood, and Paul J. W. ten Hagen. GKS - The First
Graphics Standard, @I[IEEE Computer Graphics and Applications],
July 1982, vol. 2, no. 5, pp. 9-23.}@foot{Carl Machover and Ware
Myers. Interactive Computer Graphics, @i[IEEE Computer], October
1984, pp. 145-161.}@foot{Lansing Hatfield. Progress in Graphics
Standards (Sidebar to Machover-Ware article), @i[IEEE Computer],
October 1984, p. 155.}@foot{Lansing Hatfield and Bert Herzog.
Graphics Software -- from Techniques to Principles. @i[IEEE
Computer Graphics and Applications], Jan. 1982, vol. 2, no. 1,
pp. 59-80.} GKS distinguishes itself as being easily portable
between machine installations and possessing great potential for
computer graphics software development.@foot{Clinton N. Waggoner.
The GKS Advantage, Realizing the Potential of Computer Graphics,
@i[Computer Graphics World], October 1984, pp. 19-42.} This
feature prompted Digital Research, Inc., to incorporate a
significant subset of the GKS standard into an extension of their
8- and 16-bit operating systems, CP/M-80 and CP/M-86, and IBM's
PC-DOS as well. It is known commercially as the @u[G]raphics
@u[S]ystem E@u[x]tension (GSX). However, the problem of
interfacing a language to it will remain until interfaces are
published, whole or in part, or made available by vendors. This
article provides one such interface and should allow programmers
to take full advantage of Turbo Pascal to develop a multitude of
graphics applications.
The essential ingredients of the interface require a modest
understanding of two principal parts of GSX, the @I[Graphics
Device Operating System (GDOS)] and the @I[Graphics Input Output
System (GIOS)]. The application program (in PASCAL or whatever)
requests a specific graphics function to be performed by
executing a call to that function. GDOS receives the call in its
proper form and eventually passes control to the
hardware-dependent modules in GIOS that have the job of changing
the original service request into commands acceptable to the
peripheral device. The module that exercises control over the
device is called the @i[device driver]. For each graphics
device, one device driver is required. The main point here is
that the programmer need @u[not] be concerned with the hardware
specifics of the peripheral but only with the fact that the
correct driver must be loaded as part of GSX at the time of the
request. The GSX function, OPENWORKSTATION, accomplishes the
loading of the appropriate driver. It also serves another
purpose. It returns information to the caller by exhibiting
graphics characteristics of the called device. For example, the
device may be able to draw a number of different line styles,
fonts, patterns, fill hatch styles, and displayable colors, etc.
The caller may, upon receiving this information, route control
differently than for a simpler device. GSX provides for only one
workstation to be open at a time.
OPENWORKSTATION is an example of a GSX function available upon
call. There are many such functions in GSX, and they all
operate by receiving information from the caller, performing the
graphics on the proper device (if possible), and sending back
some status and output information (if any). These principles
are displayed in Figure 1.
@center{______________________________
insert figure 1 about here
______________________________}
Now, how is a call to GSX actually made? GSX functions are in
machine code and accessible by number. For some functions GSX
requires addresses where it can expect to find such items as
number of points, an array of point coordinates, and color codes,
etc. Therefore, it is natural that GSX employ the idea of a
window in memory which contains the addresses of nearly all
pertinent graphics data to be communicated to and from GSX. This
window binds the language to GSX and is known as the @i[parameter
block]. GSX also uses the accumulator to return GDOS status
information to the caller.
Specifically, the parameter block consists of pointers to five
arrays elsewhere in memory as declared by the application
program. Each of these arrays contains the graphics data GSX
needs to perform a function. If you will now find Figure 2, you
will see that the array sizes may vary from one call to the next
thereby giving the potential, for example, of having GSX plot a
short or long sequence of connected points, called a POLYLINE,
with only one call. In the case of Pascal, the application
program must declare the maximum sizes of these arrays in TYPE
declarations. The sequence of points would be placed in the
proper array prior to the call to POLYLINE. Keep in mind that
the parameter block does not contain actual graphic data but
instead contains pointers to arrays containing the data.
Therefore, GSX poses no maximum limit on these array sizes. The
binding requirements of the programming language used to write
the interface and available memory are the factors that pose a
practical limit. Turbo Pascal presents no problem in this
regard. On 8-bit machines these pointers are 16-bit machine
addresses, and for 16-bit machines they are 32-bit segment
offsets. In all cases the arrays consist of 16-bit integers.
This latter detail will be transparent in this Turbo Pascal
implementation since 16-bit integer types are implemented.
@center{______________________________
insert figure 2 about here
______________________________}
Specifically, the parameter block contains:
@verbatim{
Pointer 1 . . . to a @I[CONTROL] array,
Pointer 2 . . . to an @I[INPUT PARAMETER] array,
Pointer 3 . . . to an @I[INPUT COORDINATE] array,
Pointer 4 . . . to an @I[OUTPUT PARAMETER] array,
Pointer 5 . . . to an @I[OUTPUT COORDINATE] array.}
Each of the above has the same purpose for each GSX function. The
individual arrays contain information defined specifically for
each GSX function although the usage pattern is consistent from
one to another. In particular, the CONTROL array contains the
following integer information:
@begin(verbatim)
1. GSX Function Code
2. Size of Input Coordinate Array
3. Size of Output Coordinate Array
4. Size of Input Parameter Array
5. Size of Output Parameter Array
@end(verbatim)
Coordinate array sizes (2 and 3 above) are always required even
if zero. Naturally, the function code (1) is also required to allow
GDOS to determine which graphics function is to be performed.
Note in Figure 3 how this control array, along with the window
parameter block, contains the information necessary for GSX to
use the remaining arrays.
@center{______________________________
insert figure 3 about here
______________________________}
For convenience the GSX functions may be grouped to illustrate
common functionality. Table 1 contains a list of these groups:
@i[Workstation Functions, Line Drawing Functions, Point
Marking Functions, Generalized Drawing Primitives (GDP's), Filled
Area Functions, Text Functions, Color Functions, Mode Control
Functions, Input Functions, and Status Inquiry Functions]. Table
2 provides a summary of the @i[ESCAPE Functions]. Each is given
with its GSX function code and the Turbo Pascal procedure name
used in subsequent listings. These functions are
device-independent, except for a few in Table 2 which are
purposely placed within the ESCAPE group where GSX provides for
device-specific functions to occur.
GDOS contains a virtual device interface which performs the
necessary coordinate mapping from @I{Normalized Device
Coordinates (NDC)}, ranging from 0 to 32767 on both x- and
y-axes, to the device-specific real coordinate space determined
by the currently loaded driver. Although the time consumed by
this transformation may seem unnecessary when compared to
accessing the device directly with device-specific code, the
advantage of device-independence is well worth the small
sacrifice in speed for most applications. Therefore, high-level
language code for graphics programs developed in this environment
is easily transported to other GSX-supported machines.
Complete details for GSX are too extensive to be presented here
but are well-documented in the references at the end of this
article. Therefore, I shall provide the major details necessary
to build the software interface between Turbo Pascal and GSX.
The resulting collection of Turbo procedures and functions will
be referred to hereafter as the
@U{Turbo Graphics Shell}.
@center{________________________________________
insert table 1 and table 2 about here
________________________________________}
@flushleft{Accessing GSX from Turbo Pascal}
Access to GSX from Turbo Pascal must be provided using the window
parameter block once all the arrays have been loaded with the
proper control and graphics information. In this, the 16-bit
version, GSX is called using software interrupt 224 with function
code 0473 hex in the CX register. The CX and DX registers are
preserved upon entry and restored upon exit. Figure 4 contains
the Turbo code in a procedure called CALLGDOS that incorporates
these requirements.
CALLGDOS is then accessed using the Turbo-supplied function
ADDR(@i{arg}), described in the Turbo Reference Manual, which
returns the memory address of @i{arg}. A call should be in the
form CALLGDOS(ADDR(PB)) where PB contains the integer address of
the window parameter block. Here I rely on a useful feature of
Turbo Pascal that permits placement of in-line machine code into
the Pascal source code. (It would be even nicer if it assembled
the mnemonic code since it would prevent having to look up the
hex code for each! Oh well, for $49.95 you can't expect a
sunroof!) The code effectively saves registers, loads the CX
register, executes the interrupt, and restores the saved
registers. For you dyed-in-the-wool Pascal programmers, this is
the only instance where machine code is needed, so don't despair!
Note however that this procedure is critical to proper
functioning of the interface.
@center{______________________________
insert figure 4 about here
______________________________}
Once called, GSX looks for the window parameter block and its
associated arrays, performs the graphics operations, and then
returns to the Pascal calling program. To accomplish this, a
procedure named SETPBLOCK is provided to assist with loading the
pointers into the window parameter block array. Its
arguments are the five integer pointers (^integer) for each of the
five integer arrays CONTRL, INTIN, PTSIN, INTOUT, and PTSOUT,
corresponding respectively to those required by GSX. Here
ADDR(PB) returns an address compatible with a
pointer-to-an-integer type (^integer). Each of these arrays will
be locally declared and therefore dynamically allocated within
each procedure since their sizes often differ. Thus, a call to
SETPBLOCK would take the form SETPBLOCK (ADDR(CONTRL),
ADDR(INTIN), ADDR(PTSIN), ADDR(INTOUT), ADDR(PTSOUT)). Finally,
once these arrays are loaded properly with data, all that remains
is a call to SETPBLOCK followed by CALLGDOS. It should be noted
that the global declarations TYPE PINTEGER:^INTEGER and VAR
PB:ARRAY[1..5] OF PINTEGER are both necessary for any Turbo
Pascal application using this GSX interface. Since Turbo Pascal
permits multiple CONST, TYPE, VAR, PROCEDURE and FUNCTION
declarations in any order, this global declaration can be
conveniently and inconspicuously placed in one disk file to be
included at compilation time. In the interest of clarity and
modularity, I have tried to keep such global declarations to a
minimum. PB is the only globally declared variable name that the
applications programmer should avoid if side effects are to be
prevented. If you wish, rename it p___b or something unusual and
forget it thereafter.
@center{______________________________
insert figure 5 about here
______________________________}
@flushleft{Some Demonstration Procedures}
The remainder of the Turbo interface to GSX consists of a set of
procedures similar in name to the GSX functions given in Table 1.
The general six-point strategy for each is to
@begin{verbatim}
1. Determine necessary value and formal parameters for
the procedure from the documented input and output
requirements for the GSX procedure,
2. Declare the five integer arrays required by the
GSX function,
3. Place the proper values into the arrays using
GSX-defined requirements,
4. Call SETPBLOCK to establish the parameter block,
5. Call CALLGDOS to pass control to GSX using the
parameter block,
6. Prepare output (if any) from GDOS and return.
@end{verbatim}
Information required by GSX is passed through the formal
parameters of a procedure or function. Returned information, if
any, is returned using variable parameters in an argument list, a
function value, or in some cases, both. Once again, to prevent
side effects, global variables are never used to carry
information from an application program to the Turbo Graphics
Shell.
@center{______________________________
insert Figure 6 about here
______________________________}
In Figure 6 for example, the procedure POLYLINE draws lines
sequentially for a given set of points passed to it. The
argument @I{npts} contains the number of coordinate pairs (x,y)
to be joined with lines in sequence. The @I{ptsin} parameter
contains a pointer to the first member of an array consisting of
(x,y) points in NDC values stored as x,y,x,y,x,y,x,y, etc. By
passing the pointer and the array size rather than the array name
itself, one is able to transfer in effect a "variably dimensioned
array" which need not be declared as an array argument of a
procedure within the Turbo Graphics Shell. Therefore,
declarations of global arrays are unnecessary even though arrays
are being passed through procedure parameter lists. The
Turbo-supplied function, ADDR(), which returns a pointer to its
argument, is the key to accomplishing this transfer when the
arrays are passed to GSX.
GSX requires the control array to be loaded with the properly
defined values. For example, the definitions of the control
array for POLYLINE are indicated in the CONTRL assignments in
Figure 6a. Note that @i[intin], @i[intout], and @i[ptsout] might
be declared as single integer variables when they require
dimension 1. The address of the start of each array is all that
is subsequently passed to the SETPBLOCK procedure. GSX knows
where to find the proper information if we load the arrays
correctly. Note in one case, that @i[ptsin] has been transferred
into POLYLINE as an actual address of an integer (^integer),
therefore the ADDR function is not used when @i[ptsin] is passed
along to SETPBLOCK. Upon return from SETPBLOCK, the parameter
block now contains the addresses of the five GSX arrays, so all
that remains is to transfer the address of the parameter block,
ADDR(PB), to GDOS. Upon its return the sequenced lines will have
been drawn on the current device.
In other cases where calls are made to the Shell, CALLGDOS will
return information for the caller to process. For example, in
the INPUTLOCATOR function in Figure 6b, CALLGDOS returns the final x and y
coordinates of the locator device (crosshair, mouse, etc.) in the
@i[ptsout] array, the success status of the input locator device
in CONTRL[5], and the character which terminated the input
locator device in the @i[intout] array. They are then placed
into the properly named VAR parameters and the function name
variable and returned to the caller of INPUTLOCATOR. Note also
that GDOS expects to receive the device number for input, the
mode of the input locator's operation, and the initial x-y
graphics cursor position of the locator. Sample mode implies
that the device will return the x-y coordinates continually as
the device is moved until a terminator character occurs, while
request mode will permit initial positioning of the cursor and a
subsequent final x-y position returned once the terminator
character occurs.
@center{
______________________________
Figure 7 about here
______________________________}
Turbo procedures mentioned in Table 1, which are also detailed in
Listing 1, all operate on the six-point strategy. Some are
further modularized. For instance, in Figure 7, quite a few of
the ESCAPE functions, such as ENTERGRAPHICS, call a utility named
ASNCTL which merely assigns transferred values to the control
array and then calls SETPBLOCK and CALLGDOS resulting in a
savings in code size. Many of the ESCAPE functions differ only
in the values assigned to elements of the control array.
@flushleft{Implementation Notes}
The function groups containing the procedures shown in Table 1
should be assigned to separate source code files for inclusion
with an application program when it is to be compiled under Turbo
Pascal. Turbo does not permit linking to separately compiled
object code files. Therefore, each GSX function group that is
used must be included from disk as part of the programmer's
source code each time it is compiled. My advice here is to save
the function groups in separate disk files such as GSXWORK.INC,
GSXLINE.INC, etc. and then use the Turbo "include" compiler
comment option, {$Idrv:filename.ext}, to include the desired
ones, e.g. {$IB:GSXWORK.INC} which will include the file
containing the workstation functions, GSXWORK.INC, from the B:
drive at compilation time. (You may leave a space between the
"I" and the "B:" in this comment. However, I like to use Turbo's
TLIST program to selectively list included files, and
unfortunately, TLIST aborts if the space is present in the
comment. Not a serious problem but, Borland, if you are reading
this, how about fixing it?)
Noteworthy here is Turbo's non-standard placement of CONST, TYPE,
VAR, FUNCTION and PROCEDURE declarations permitting any number of
these declarations to occur in any order. As a matter of
convenience, I chose to hide the global declarations for PINTEGER
and PB with the workstation functions. These functions must
always be included as the first included file if the Shell is to
be used. For example, Listing 2 contains a skeleton program
which suggests how to include the GSX function groups needed for
a typical compilation. Include only those groups (files) which
contain procedures needed by the application program. If the
whole Turbo Graphics Shell is included, the programmer can expect
worst case compilation times of about 60 seconds for the Shell
alone. The full Shell consumes about 9K bytes of memory once
compiled.
For those of you who may be neophytes with Turbo Pascal, it is
advisable that the complete code be test-compiled using the
skeleton main program. The Turbo editor is superb for this
process. Declare the "MAIN" file as SHELL.PAS and compile it
into memory with the first included file, then the second, etc.
Typing errors made while entering the included files will be
flagged. The editor will be kind enough to pinpoint the first
error, automatically enter edit mode, and place the cursor on the
error location. Once the correction is made to source code in an
included file and a request to re-compile is given, the included
file with corrections is automatically saved and the main file is
loaded into memory and compilation begins. In this way, the
editor provides an excellent semi-intelligent edit/compile/run
environment. The compiler and editor are sufficiently fast so
that this process resembles a session with an interactive BASIC
interpreter. Debugging a graphics program is remarkably easy and
fast with Turbo and at times is even enjoyable since there is no
time-consuming link and load process after compilation.
@flushleft{Final Remarks}
The Turbo Graphics Shell contained here conforms to requirements
necessary to interface Turbo Pascal to the Graphics System
Extension (GSX-86 Kernel) available from Digital Research, Inc.
It provides programmers of GSX-equipped micros running CP/M with
a means to code graphics applications easily and productively
using the full features provided by the edit, compile, and
run-time environment within Turbo Pascal. The implementer is
expected to be familiar with Pascal and have the necessary device
drivers usually supplied by the machine's vendor. The Turbo
Graphics Shell described here was implemented successfully on a
DEC Rainbow 100A by the author and is currently being used to
develop a Turbo Graphics Software Tool Kit and numerous
demonstration programs exploiting the features of GSX, the
Rainbow, and Turbo Pascal.
Source code for the Shell is available on disk in either Rainbow
or standard 8" CP/M format from the author for $20.00 or may be
downloaded using the @i[Computer Language] Compuserve account.
Complete source listings and demo programs are available in
hardcopy form from the author for $5.00/set. Proceeds will be
given to the University of Pittsburgh at Johnstown ACM Student
Chapter to support student software projects. Address inquiries
to:
@begin{verbatim}
Hubert D. Callihan, Ph.D.
Computer Science Department
University of Pittsburgh at Johnstown
Johnstown, Pa 15904
@end{verbatim}
is
expected to be familiar with Pascal and have the necessary device
drivers usually supp